// Roger's coding area
// .h acting like cpp for speed?


#pragma once

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#include <glut.h>
#include <conio.h>

	// set up the lighting
GLfloat lightPosition0[] = {2.0, 0.0, -2.0, 1.0}; // the light postion 0
GLfloat lightAmbient0[] =  {0.0, 0.0, 0.0, 1.0};  // what's just there
GLfloat lightDiffuse0[] =  {1.0, 1.0, 1.0, 1.0};  // whats's absorbed
GLfloat lightSpecular0[] = {0.5, 0.5, 0.5, 1.0};  // what's reflected ( a white spot)
GLfloat globalAmbientLight[] = {0.2f, 0.2f, 0.2f, 1.0f}; // very little light

GLfloat worldYrotate = 0.0;

static GLfloat eyeX = 0.0;
static GLfloat eyeY = 0.0;
static GLfloat eyeZ = 0.0;
int dir = 0; // init direction of Sphere is down

static GLuint startList; // for glu sphere

using namespace System::Windows::Forms;


namespace OpenGLForm 
{

	public ref class COpenGL: public System::Windows::Forms::NativeWindow
	{
	public:  // COpenGL constructor 
		COpenGL(System::Windows::Forms::Form ^ parentForm, GLsizei iWidth, GLsizei iHeight)
		{
			CreateParams^ cp = gcnew CreateParams;

			// Set the position on the form
			cp->X = 0;
			cp->Y = 0;
			cp->Height = iHeight;
			cp->Width = iWidth;

			// Specify the form as the parent.
			cp->Parent = parentForm->Handle;

			// Create as a child of the specified parent and make OpenGL compliant (no clipping)
			cp->Style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

			// Create the actual window
			this->CreateHandle(cp);

			m_hDC = GetDC((HWND)this->Handle.ToPointer());

			if(m_hDC)
			{
				MySetPixelFormat(m_hDC);        // calls to local functions (me)
				ReSizeGLScene(iWidth, iHeight);
				InitGL();
			}

			
			tSphere = 20.0f; // set initial hight
		}

	/*System::Void keyboard(unsigned char key, int x, int y)
		{
			switch(key)
			{
				case 'q':
					eyeX += 1.0;
					eyeZ -=1.0;
					glFlush();
					break;

				case 'w':
					eyeX -= 1.0;
					eyeZ += 1.0;
					glFlush();
					break;

				case 'a':					
					eyeZ +=1.0;
					glFlush();
					`			break;

				case 's':					
					eyeZ -=1.0;
					glFlush();
					break;
			}
		}

		/*System::Void keyboard(System::Void)
		{
			if (WM_KEYDOWN)
			//if (_kbhit()) // see if a key is pressed
			{
				switch(_getch()) // edit : if you want to check the arrow-keys you must call getch twice because special-keys have two values
				{
					
					case 'q':
					eyeX += 1.0;
					eyeZ -=1.0;
					//glFlush();
					break;

				case 'w':
					eyeX -= 1.0;
					eyeZ += 1.0;
					//glFlush();
					break;

				case 'a':					
					eyeZ +=1.0;
					//glFlush();
					break;

				case 's':					
					worldYrotate -= 1.0;
					glFlush();
					break;
				}

			}
			
		}*/

		System::Void changeEyeY(System::Void)
		{
			eyeY += 0.2f;
		}



		System::Void Render(System::Void)						// display the graphics
		{
			       //new cord
			if (dir == 0)
			{ 				
				tSphere -= 0.2f;
				if (tSphere <= -10.0f) dir = 1; // up
			}
			else
			{				
				tSphere += 0.2f;
				if (tSphere >= 10.5f) dir = 0; // down
			}
			

			//eyeX += .2f;
			//eyeY += .2f;
			//eyeZ += .2f;

			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear screen color and depth buffer
			glEnable(GL_COLOR_MATERIAL);															
			glLoadIdentity();									// Reset the current modelview matrix
			//gluLookAt(eyeX, eyeY, eyeZ,  0.0, 0.0, 0.0,  0.0, 1.0, 0.0);
			glRotatef(worldYrotate, 0.0f, 0.1f, 0.0f);

		/*	glPushMatrix();

			glTranslatef(-1.5,0.0,-6.0);						// Move left 1.5 units and into the screen 6.0
			//glRotatef(rtri,0.0f,1.0f,0.0f);						// Rotate the triangle on the y axis 

			glBegin(GL_TRIANGLES);								// Start drawing a triangle
				glColor3f(1.0f,0.0f,0.0f);						// Red

				glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of triangle (front)				
				glVertex3f(-1.0f,-1.0f, 1.0f);					// Left of triangle (front)				
				glVertex3f( 1.0f,-1.0f, 1.0f);					// Right of triangle (front)
				
				glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of triangle (right)				
				glVertex3f( 1.0f,-1.0f, 1.0f);					// Left of triangle (right)				
				glVertex3f( 1.0f,-1.0f, -1.0f);					// Right of triangle (right)
				
				glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of triangle (back)				
				glVertex3f( 1.0f,-1.0f, -1.0f);					// Left of triangle (back)				
				glVertex3f(-1.0f,-1.0f, -1.0f);					// Right of triangle (back)
				
				glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of triangle (left)				
				glVertex3f(-1.0f,-1.0f,-1.0f);					// Left of triangle (left)				
				glVertex3f(-1.0f,-1.0f, 1.0f);					// Right of triangle (left)

			glEnd();											// Done drawing the pyramid

			glPopMatrix(); */

			glPushMatrix();

				glLoadIdentity();
				glTranslatef(0, tSphere, -30);
				glColor3f(0.0f, 1.0f, 0.0f);			                // Dk green
				glCallList(startList);									// place pshere here
				//glutSolidSphere(1.0, 30, 7);                        // make a sphere

			glPopMatrix();
			
			glPushMatrix();

				glLoadIdentity();									// Reset the current modelview matrix
				glTranslatef(0.0f, 0.0f, 9.0f);						// Move right 1.5 units and into the screen 7.0
				//glRotatef(rquad,1.0f,1.0f,1.0f);					// Rotate the quad on the x axis 
			
				glBegin(GL_QUADS);	 					     		// Draw floor	
					glColor3f(1.0f, 0.9f, 0.3f);					// tan color
					glVertex3f(-30, -20, -80);					    // Top Right of the quad (top)
					glColor3f(1.0f, 1.0f, 0.5f);
					glVertex3f(-30, -20, 0);					    // Top Left of the quad (top)
					glVertex3f(30, -20, 0);
					glColor3f(1.0f, 0.9f, 0.3f);
					glVertex3f(30, -20, -80);					    // Bottom left of the quad (top)

					glVertex3f(25, -20, -80);					    // Bottom right of the quad (top)				
				glEnd();											// Done drawing the quad	

			glPopMatrix();
													
		}


		System::Void SwapOpenGLBuffers(System::Void)
		{
			SwapBuffers(m_hDC) ;
		}

	private:
		HDC m_hDC;
		HGLRC m_hglrc;
		GLfloat	tTri;				// Angle for the triangle
		GLfloat	tSphere;			// translation for sphere

	protected:
		~COpenGL(System::Void)
		{
			this->DestroyHandle();
		}

		GLint MySetPixelFormat(HDC hdc)
		{
			static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
				{
					sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
					1,											// Version Number
					PFD_DRAW_TO_WINDOW |						// Format Must Support Window
					PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
					PFD_DOUBLEBUFFER,							// Must Support Double Buffering
					PFD_TYPE_RGBA,								// Request An RGBA Format
					16,										    // Select Our Color Depth
					0, 0, 0, 0, 0, 0,							// Color Bits Ignored
					0,											// No Alpha Buffer
					0,											// Shift Bit Ignored
					0,											// No Accumulation Buffer
					0, 0, 0, 0,									// Accumulation Bits Ignored
					16,											// 16Bit Z-Buffer (Depth Buffer)  
					0,											// No Stencil Buffer
					0,											// No Auxiliary Buffer
					PFD_MAIN_PLANE,								// Main Drawing Layer
					0,											// Reserved
					0, 0, 0										// Layer Masks Ignored
				};
			
			GLint  iPixelFormat; 
		 
			// get the device context's best, available pixel format match 
			if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
			{
				MessageBox::Show("ChoosePixelFormat Failed");
				return 0;
			}
			 
			// make that match the device context's current pixel format 
			if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
			{
				MessageBox::Show("SetPixelFormat Failed");
				return 0;
			}

			if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
			{
				MessageBox::Show("wglCreateContext Failed");
				return 0;
			}

			if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
			{
				MessageBox::Show("wglMakeCurrent Failed");
				return 0;
			}


			return 1;
		}
		//------------------------------------------------------------------------------------------------------------
		bool InitGL(GLvoid)										// All setup for opengl goes here (called once by the class constructor)
		{	
			
			glClearColor(0.8f, 0.8f, 1.0f, 0.0);				// Lt blue background
			glShadeModel(GL_SMOOTH);							// Enable smooth shading
			glClearDepth(1.0f);									// Depth buffer setup
			glEnable(GL_DEPTH_TEST);							// Enables depth testing
			glDepthFunc(GL_LEQUAL);								// The type of depth testing to do
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really nice perspective calculations
			
			glLightfv(GL_LIGHT0, GL_POSITION, lightPosition0);
			glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient0);
			glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse0);			
			glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular0);

			glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbientLight);
			glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
			glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);  
			glEnable(GL_LIGHTING);
			glEnable(GL_LIGHT0);
			
			GLUquadricObj *qobj;
			glShadeModel(GL_SMOOTH);
			startList = glGenLists(1); // one sphere object to make
			qobj = gluNewQuadric();
			gluQuadricDrawStyle(qobj, GLU_FILL);
			gluQuadricNormals(qobj, GLU_SMOOTH);
			glNewList(startList, GL_COMPILE);
			  gluSphere(qobj, 1.0, 30, 10);
			glEndList();

			return TRUE;										// Initialisation went ok
		}
		//-------------------------------------------------------------------------------------------------
		GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize and initialise the gl window
		{
			if (height==0)   									// Prevent A Divide By Zero By
			{
				height=1;										// Making Height Equal One
			}
			glViewport(0,0,width,height);						// Reset The Current Viewport
			glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
			glLoadIdentity();									// Reset The Projection Matrix			
			gluPerspective(60.0f, (GLfloat)width/(GLfloat)height, 0.1f, 200.0f); // Calculate The Aspect Ratio Of The Window
			glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
			glLoadIdentity();									// Reset The Modelview Matrix
			gluLookAt(eyeX, eyeY, eyeZ,  0.0, 0.0, 0.0,  0.0, 1.0, 0.0);
		}
	};
}